<?php

class My_Html_Layout
{
    /**
     * @var string
     */
    protected $id;
    /**
     * @var array
     */
    protected $rows = array();
    /**
     * @var array
     */
    protected $backgroundColors = array();
    /**
     * @var array
     */
    protected $styles = array();
    /**
     * @var boolean 
     */
    protected $autoWidth = true;
    /**
     *
     * @var array
     */
    protected $contents = array();

    protected function  __construct($id = null, $layout = array())
    {
        $this->id = $id;
        $this->rows = $layout;
    }

    /**
     *
     * @param string $id
     * @param array $layout
     * @return My_Html_Layout
     */
    public static function factory($id = null, $layout = null)
    {
        if (is_null($id)) $id = uniqid ();
        return new self($id, $layout);
    }

    /**
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param string $id
     * @return My_Html_Layout
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     * @return array
     */
    public function getLayout()
    {
        return $this->rows;
    }

    /**
     * @param array $layout
     * @return My_Html_Layout
     */
    public function setLayout($layout)
    {
        $this->rows = $layout;
        return $this;
    }

    /**
     * @param integer $numOfColumns
     * @return My_Html_Layout
     */
    public function addRow($numOfColumns)
    {
        $this->rows[] = $numOfColumns;
        return $this;
    }

    /**
     * @param integer $rowNumber
     * @param integer $numOfColumns
     * @return My_Html_Layout 
     */
    public function setNumOfColumns($rowNumber, $numOfColumns)
    {
        $this->rows[$rowNumber] = $numOfColumns;
        return $this;
    }
    
    /**
     * @param boolean $value
     * @return My_Html_Layout 
     */
    public function autoWidth($value = true)
    {
        $this->autoWidth = $value;
        return $this;
    }

    /**
     * @param string $className
     * @param integer $rowNumber
     * @param integer $columnNumber
     * @return My_Html_Layout 
     */
    public function addClass($className, $rowNumber, $columnNumber)
    {
        if ( !isset ($this->rows[$rowNumber])
                ||
                ( isset ($this->rows[$rowNumber]) && $columnNumber > $this->rows[$rowNumber]-1 ) ) throw new Exception('No existe posición '.$rowNumber.', '.$columnNumber.' en el panel de distribucióm '.$this->getId());
        if (!isset($this->styles[$rowNumber]) || isset($this->styles[$rowNumber]) && !isset ($this->styles[$rowNumber][$columnNumber])) 
        {
            $this->styles[$rowNumber][$columnNumber][] = $className;
        }
        else
        {
            $this->styles[$rowNumber][$columnNumber][] = $className;
        }
        return $this;
    }
    
    /**
     * @param integer $rowNumber
     * @param integer $columnNumber
     * @param boolean $returnString
     * @return string | array
     */
    public function getClasses($rowNumber, $columnNumber, $returnString = true)
    {
        $styles = array();
        if (isset($this->styles[$rowNumber][$columnNumber])) $styles = $this->styles[$rowNumber][$columnNumber];
        if (true == $returnString)
        {
            $styles = trim(implode(' ', $styles));
        }
        return $styles;
    }

    /**
     * @param mixed $content
     * @param integer $rowNumber
     * @param integer $columnNumber
     * @return My_Html_Layout
     */
    public function addContent($content, $rowNumber = null, $columnNumber = null)
    {
        if (!is_null($rowNumber) && !is_null($columnNumber))
        {
            if ( !isset ($this->rows[$rowNumber])
                ||
                ( isset ($this->rows[$rowNumber]) && $columnNumber > $this->rows[$rowNumber]-1 ) ) throw new Exception('No existe posición '.$rowNumber.', '.$columnNumber.' en el panel de distribucióm '.$this->getId());
            
            $this->contents[$rowNumber][$columnNumber] = $content;
        }
        elseif (!is_null($rowNumber) && is_null($columnNumber))
        {
            list($freeRow, $freeColumn) = $this->getFirstFreePlaceHolder($rowNumber);
            $this->contents[$rowNumber][$freeColumn] = $content;
        }
        elseif (is_null($rowNumber) && is_null($columnNumber))
        {
            list($freeRow, $freeColumn) = $this->getFirstFreePlaceHolder();
            $this->contents[$freeRow][$freeColumn] = $content;
        }
        return $this;
    }


    /**
     * @param string $row
     * @return array array($rowNum, $columnNum)
     */
    public function getFirstFreePlaceHolder($row = null)
    {
        $firstFreePlaceHolder = null;
        if (!is_null($row))
        {
            if (!isset ($this->rows[$row])) throw new Exception ('Row not found '. $row);
            for ($i= 0; $i < $this->rows[$row]; $i++)
            {
                if (is_null($this->contents[$row][$i]) || !isset ($this->contents[$row][$i]))
                {
                    $firstFreePlaceHolder = array($row, $i);
                    break;
                }
            }
            if (is_null($firstFreePlaceHolder)) throw new Exception ('No free place holder found in row '.$row);
        }

        else
        {
            foreach ($this->getLayout() as $rowNum=>$NumberOfColumns)
            {
                for ($ColumnNumber = 0; $ColumnNumber < $NumberOfColumns; $ColumnNumber++)
                {
                    if (!isset ($this->contents[$rowNum][$ColumnNumber]) || is_null($this->contents[$rowNum][$ColumnNumber]))
                    {
                        $firstFreePlaceHolder = array($rowNum, $ColumnNumber);
                        break;
                    }
                }
                if (is_array($firstFreePlaceHolder)) break;
            }
            if (is_null($firstFreePlaceHolder)) throw new Exception ('No free place holders');
        }
        return $firstFreePlaceHolder;
    }

    /**
     * @return string
     */
    public function render()
    {
        $code = sprintf('<div id="%s-layout" name="layout" class="layout">', $this->getId());
        if (is_array($this->getLayout()) && count($this->getLayout())>0)
        {            
            foreach ($this->getLayout() as $rowNumber => $numberOfColumns)
            {
                $code .= sprintf('<div id="%s-row-%s" class="row-layout">', $this->getId(), $rowNumber);
                $columnWidth = floor(100/$numberOfColumns);
                for($i = 0; $i<$numberOfColumns; $i++)
                {
                    $columnsContents = '';
                    if (isset ($this->contents[$rowNumber][$i]) && !is_null($this->contents[$rowNumber][$i]))
                    {
                        $columnsContents = $this->contents[$rowNumber][$i];
                        if (!is_string($columnsContents)) $columnsContents = $columnsContents->__toString();
                    }
                    $extraClasses = '';
                    $autoWidthClass = '';
                    if (strlen($this->getClasses($rowNumber, $i))>0) $extraClasses .= ' '.$this->getClasses($rowNumber, $i); 
                    if (true == $this->autoWidth) $autoWidthClass = sprintf(' column%sx100', $columnWidth);
                    $code .= sprintf('<div class="layout-place-holder%s%s" name="place-holder-%s-%s">%s</div>', 
                            $autoWidthClass, 
                            $extraClasses, 
                            $rowNumber, 
                            $i, 
                            $columnsContents);
                }
                $code .= '</div>';
            }
        }
        $code .= '</div>';
        return $code;
    }

    /**
     * @return string
     */
    public function  __toString()
    {
        $html = '';
        try
        {
            $html = $this->render();
        }
        catch(Exception $e)
        {
            $html = sprintf('Error rendering panel %s (%s).', $this->getId() ,$e->getMessage());
        }
        return $html;
    }
}
